<?php

// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: 麥當苗兒 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------

namespace Admin\Controller;

use Think\Controller;
use Admin\Model\AuthRuleModel;
use Admin\Model\AuthGroupModel;

/**
 * 後臺首頁控制器
 * @author 麥當苗兒 <zuojiazi@vip.qq.com>
 */
class AdminController extends Controller {

    private $cate_id = null; //文檔分類id

    /**
     * 後臺控制器初始化
     */

    protected function _initialize() {
        // 獲取當前用戶ID
        define('UID', is_login());
        if (!UID) {// 還沒登錄 跳轉到登錄頁面
            $this->redirect('Public/login');
        }
        /* 讀取數據庫中的配置 */
        $config = S('DB_CONFIG_DATA');
        if (!$config) {
            $config = api('Config/lists');
            S('DB_CONFIG_DATA', $config);
        }
        C($config); //添加配置
        // 是否是超級管理員
        define('IS_ROOT', is_administrator());
        if (!IS_ROOT && C('ADMIN_ALLOW_IP')) {
            // 檢查IP地址訪問
            if (!in_array(get_client_ip(), explode(',', C('ADMIN_ALLOW_IP')))) {
                $this->error('403:禁止訪問');
            }
        }
        // 檢測訪問權限
        $access = $this->accessControl();
        if ($access === false) {
            $this->error('403:禁止訪問');
        } elseif ($access === null) {
            $dynamic = $this->checkDynamic(); //檢測分類欄目有關的各項動態權限
            if ($dynamic === null) {
                //檢測非動態權限
                $rule = strtolower(MODULE_NAME . '/' . CONTROLLER_NAME . '/' . ACTION_NAME);
                if (!$this->checkRule($rule, array('in', '1,2'))) {
                    $this->error('未授權訪問!');
                }
            } elseif ($dynamic === false) {
                $this->error('未授權訪問!');
            }
        }
        if (!IS_AJAX) {
            $this->getMenu();
            //print_r(M('Menu')->where("url like '%" . CONTROLLER_NAME . "/" . ACTION_NAME . "%'")->find());
            $this->assign('__current__', $meun = M('Menu')->where("url like '%" . CONTROLLER_NAME . "/" . ACTION_NAME . "%'")->field('id,pid,group,title')->find());
            $menunav = D('Menu')->getPath($meun['id']);
            $this->assign('__nav__', $menunav[0]);
        }
    }

    /**
     * 權限檢測
     * @param string  $rule    檢測的規則
     * @param string  $mode    check模式
     * @return boolean
     * @author 朱亞傑  <xcoolcc@gmail.com>
     */
    final protected function checkRule($rule, $type = AuthRuleModel::RULE_URL, $mode = 'url') {
        if (IS_ROOT) {
            return true; //管理員允許訪問任何頁面
        }
        static $Auth = null;
        if (!$Auth) {
            $Auth = new \Think\Auth();
        }
        if (!$Auth->check($rule, UID, $type, $mode)) {
            return false;
        }
        return true;
    }

    /**
     * 檢測是否是需要動態判斷的權限
     * @return boolean|null
     *      返回true則表示當前訪問有權限
     *      返回false則表示當前訪問無權限
     *      返回null，則會進入checkRule根據節點授權判斷權限
     *
     * @author 朱亞傑  <xcoolcc@gmail.com>
     */
    protected function checkDynamic() {
        if (IS_ROOT) {
            return true; //管理員允許訪問任何頁面
        }
        return null; //不明,需checkRule
    }

    /**
     * action訪問控制,在 **登陸成功** 後執行的第壹項權限檢測任務
     *
     * @return boolean|null  返回值必須使用 `===` 進行判斷
     *
     *   返回 **false**, 不允許任何人訪問(超管除外)
     *   返回 **true**, 允許任何管理員訪問,無需執行節點權限檢測
     *   返回 **null**, 需要繼續執行節點權限檢測決定是否允許訪問
     * @author 朱亞傑  <xcoolcc@gmail.com>
     */
    final protected function accessControl() {
        if (IS_ROOT) {
            return true; //管理員允許訪問任何頁面
        }
        $allow = C('ALLOW_VISIT');
        $deny = C('DENY_VISIT');
        $check = strtolower(CONTROLLER_NAME . '/' . ACTION_NAME);
        if (!empty($deny) && in_array_case($check, $deny)) {
            return false; //非超管禁止訪問deny中的方法
        }
        if (!empty($allow) && in_array_case($check, $allow)) {
            return true;
        }
        return null; //需要檢測節點權限
    }

    /**
     * 對數據表中的單行或多行記錄執行修改 GET參數id為數字或逗號分隔的數字
     *
     * @param string $model 模型名稱,供M函數使用的參數
     * @param array  $data  修改的數據
     * @param array  $where 查詢時的where()方法的參數
     * @param array  $msg   執行正確和錯誤的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
     *                     url為跳轉頁面,ajax是否ajax方式(數字則為倒數計時秒數)
     *
     * @author 朱亞傑  <zhuyajie@topthink.net>
     */
    final protected function editRow($model, $data, $where, $msg) {
        $id = array_unique((array) I('id', 0));
        $id = is_array($id) ? implode(',', $id) : $id;
        $where = array_merge(array('id' => array('in', $id)), (array) $where);
        $msg = array_merge(array('success' => '操作成功！', 'error' => '操作失敗！', 'url' => '', 'ajax' => IS_AJAX), (array) $msg);
        if (M($model)->where($where)->save($data) !== false) {
            $this->success($msg['success'], $msg['url'], $msg['ajax']);
        } else {
            $this->error($msg['error'], $msg['url'], $msg['ajax']);
        }
    }

    /**
     * 禁用條目
     * @param string $model 模型名稱,供D函數使用的參數
     * @param array  $where 查詢時的 where()方法的參數
     * @param array  $msg   執行正確和錯誤的消息,可以設置四個元素 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
     *                     url為跳轉頁面,ajax是否ajax方式(數字則為倒數計時秒數)
     *
     * @author 朱亞傑  <zhuyajie@topthink.net>
     */
    protected function forbid($model, $where = array(), $msg = array('success' => '狀態禁用成功！', 'error' => '狀態禁用失敗！')) {
        $data = array('status' => 0);
        $this->editRow($model, $data, $where, $msg);
    }

    /**
     * 恢復條目
     * @param string $model 模型名稱,供D函數使用的參數
     * @param array  $where 查詢時的where()方法的參數
     * @param array  $msg   執行正確和錯誤的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
     *                     url為跳轉頁面,ajax是否ajax方式(數字則為倒數計時秒數)
     *
     * @author 朱亞傑  <zhuyajie@topthink.net>
     */
    protected function resume($model, $where = array(), $msg = array('success' => '狀態恢復成功！', 'error' => '狀態恢復失敗！')) {
        $data = array('status' => 1);
        $this->editRow($model, $data, $where, $msg);
    }

    /**
     * 還原條目
     * @param string $model 模型名稱,供D函數使用的參數
     * @param array  $where 查詢時的where()方法的參數
     * @param array  $msg   執行正確和錯誤的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
     *                     url為跳轉頁面,ajax是否ajax方式(數字則為倒數計時秒數)
     * @author huajie  <banhuajie@163.com>
     */
    protected function restore($model, $where = array(), $msg = array('success' => '狀態還原成功！', 'error' => '狀態還原失敗！')) {
        $data = array('status' => 1);
        $where = array_merge(array('status' => -1), $where);
        $this->editRow($model, $data, $where, $msg);
    }

    /**
     * 條目假刪除
     * @param string $model 模型名稱,供D函數使用的參數
     * @param array  $where 查詢時的where()方法的參數
     * @param array  $msg   執行正確和錯誤的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
     *                     url為跳轉頁面,ajax是否ajax方式(數字則為倒數計時秒數)
     *
     * @author 朱亞傑  <zhuyajie@topthink.net>
     */
    protected function delete($model, $where = array(), $msg = array('success' => '刪除成功！', 'error' => '刪除失敗！')) {
        $data['status'] = -1;
        $data['update_time'] = NOW_TIME;
        $this->editRow($model, $data, $where, $msg);
    }

    /**
     * 設置壹條或者多條數據的狀態
     */
    public function setStatus($Model = CONTROLLER_NAME) {

        $ids = I('request.ids');
        $status = I('request.status');
        if (empty($ids)) {
            $this->error('請選擇要操作的數據');
        }

        $map['id'] = array('in', $ids);
        switch ($status) {
            case -1 :
                $this->delete($Model, $map, array('success' => '刪除成功', 'error' => '刪除失敗'));
                break;
            case 0 :
                $this->forbid($Model, $map, array('success' => '禁用成功', 'error' => '禁用失敗'));
                break;
            case 1 :
                $this->resume($Model, $map, array('success' => '啟用成功', 'error' => '啟用失敗'));
                break;
            default :
                $this->error('參數錯誤');
                break;
        }
    }

    /**
     * 獲取控制器菜單數組,二級菜單元素位於壹級菜單的'_child'元素中
     * @author 朱亞傑  <xcoolcc@gmail.com>
     */
    final public function getMenus($controller = CONTROLLER_NAME) {
        // $menus  =   session('ADMIN_MENU_LIST'.$controller);
        if (empty($menus)) {
            // 獲取主菜單
            $where['pid'] = 0;
            $where['hide'] = 0;
            if (!C('DEVELOP_MODE')) { // 是否開發者模式
                $where['is_dev'] = 0;
            }

            foreach (M('Menu')->where($where)->order('sort asc')->select() as $k => $item) {
                if (!is_array($item) || empty($item['title']) || empty($item['url'])) {
                    $this->error('控制器基類$menus屬性元素配置有誤');
                }
                if (stripos($item['url'], MODULE_NAME) !== 0) {
                    $item['url'] = MODULE_NAME . '/' . $item['url'];
                }
                // 判斷主菜單權限
                if (!IS_ROOT && !$this->checkRule($item['url'], AuthRuleModel::RULE_MAIN, null)) {
                    continue; //繼續循環
                }
                $menus[$k] = $item;
                //生成child樹
                $groups = M('Menu')->where("pid = {$item['id']}")->distinct(true)->field("`group`")->select();
                if ($groups) {
                    $groups = array_column($groups, 'group');
                } else {
                    $groups = array();
                }
                //獲取二級分類的合法url
                $where = array();
                $where['pid'] = $item['id'];
                $where['hide'] = 0;
                if (!C('DEVELOP_MODE')) { // 是否開發者模式
                    $where['is_dev'] = 0;
                }
                $second_urls = M('Menu')->where($where)->getField('id,url');

                if (!IS_ROOT) {
                    // 檢測菜單權限
                    $to_check_urls = array();
                    foreach ($second_urls as $key => $to_check_url) {
                        if (stripos($to_check_url, MODULE_NAME) !== 0) {
                            $rule = MODULE_NAME . '/' . $to_check_url;
                        } else {
                            $rule = $to_check_url;
                        }
                        if ($this->checkRule($rule, AuthRuleModel::RULE_URL, null))
                            $to_check_urls[] = $to_check_url;
                    }
                }
                // 按照分組生成子菜單樹
                foreach ($groups as $g) {
                    if (empty($g))
                        continue;
                    $map = array('group' => $g);
                    if (isset($to_check_urls)) {
                        if (empty($to_check_urls)) {
                            // 沒有任何權限
                            continue;
                        } else {
                            $map['url'] = array('in', $to_check_urls);
                        }
                    }
                    $map['pid'] = $item['id'];
                    $map['hide'] = 0;
                    if (!C('DEVELOP_MODE')) { // 是否開發者模式
                        $map['is_dev'] = 0;
                    }
                    $menuList = M('Menu')->where($map)->field('id,pid,title,url,tip')->order('sort asc')->select();
                    $menus[$k]['child'][$g] = list_to_tree($menuList, 'id', 'pid', 'operater', $item['id']);
                }
                if ($menus[$k]['child'] === array()) {
                    //$this->error('主菜單下缺少子菜單，請去系統=》後臺菜單管理裏添加');
                }
            }
        }
//        $this->getMenu();
//       print_r($menus);
        return $menus;
        /*            $menus['main'] = M('Menu')->where($where)->order('sort asc')->select();

          $menus['child'] = array(); //設置子節點
          //高亮主菜單
          $current = M('Menu')->where("url like '%{$controller}/" . ACTION_NAME . "%'")->field('id')->find();
          if ($current) {
          $nav = D('Menu')->getPath($current['id']);
          $nav_first_title = $nav[0]['title'];

          foreach ($menus['main'] as $key => $item) {
          if (!is_array($item) || empty($item['title']) || empty($item['url'])) {
          $this->error('控制器基類$menus屬性元素配置有誤');
          }
          if (stripos($item['url'], MODULE_NAME) !== 0) {
          $item['url'] = MODULE_NAME . '/' . $item['url'];
          }
          // 判斷主菜單權限
          if (!IS_ROOT && !$this->checkRule($item['url'], AuthRuleModel::RULE_MAIN, null)) {
          unset($menus['main'][$key]);
          continue; //繼續循環
          }

          // 獲取當前主菜單的子菜單項
          if ($item['title'] == $nav_first_title) {
          $menus['main'][$key]['class'] = 'current';
          //生成child樹
          $groups = M('Menu')->where("pid = {$item['id']}")->distinct(true)->field("`group`")->select();
          if ($groups) {
          $groups = array_column($groups, 'group');
          } else {
          $groups = array();
          }

          //獲取二級分類的合法url
          $where = array();
          $where['pid'] = $item['id'];
          $where['hide'] = 0;
          if (!C('DEVELOP_MODE')) { // 是否開發者模式
          $where['is_dev'] = 0;
          }
          $second_urls = M('Menu')->where($where)->getField('id,url');

          if (!IS_ROOT) {
          // 檢測菜單權限
          $to_check_urls = array();
          foreach ($second_urls as $key => $to_check_url) {
          if (stripos($to_check_url, MODULE_NAME) !== 0) {
          $rule = MODULE_NAME . '/' . $to_check_url;
          } else {
          $rule = $to_check_url;
          }
          if ($this->checkRule($rule, AuthRuleModel::RULE_URL, null))
          $to_check_urls[] = $to_check_url;
          }
          }
          // 按照分組生成子菜單樹
          foreach ($groups as $g) {
          $map = array('group' => $g);
          if (isset($to_check_urls)) {
          if (empty($to_check_urls)) {
          // 沒有任何權限
          continue;
          } else {
          $map['url'] = array('in', $to_check_urls);
          }
          }
          $map['pid'] = $item['id'];
          $map['hide'] = 0;
          if (!C('DEVELOP_MODE')) { // 是否開發者模式
          $map['is_dev'] = 0;
          }
          $menuList = M('Menu')->where($map)->field('id,pid,title,url,tip')->order('sort asc')->select();
          $menus['child'][$g] = list_to_tree($menuList, 'id', 'pid', 'operater', $item['id']);
          }
          if ($menus['child'] === array()) {
          //$this->error('主菜單下缺少子菜單，請去系統=》後臺菜單管理裏添加');
          }
          }
          }
          }
          // session('ADMIN_MENU_LIST'.$controller,$menus);
          }
          return $menus;
         * */
    }

    /**
     * 顯示左邊菜單，進行權限控制
     * @author huajie <banhuajie@163.com>
     */
    protected function getMenu() {
        $Menus = $this->getMenus();
        //獲取動態分類
        $cate_auth = AuthGroupModel::getAuthCategories(UID); //獲取當前用戶所有的內容權限節點
        $cate_auth = $cate_auth == null ? array() : $cate_auth;
        $cate = M('Category')->where(array('status' => 1))->field('id,title,pid,allow_publish')->order('pid,sort')->select();
        //沒有權限的分類則不顯示
        if (!IS_ROOT) {
            foreach ($cate as $key => $value) {
                if (!in_array($value['id'], $cate_auth)) {
                    unset($cate[$key]);
                }
            }
        }

        $cate = list_to_tree($cate); //生成分類樹
       
        //獲取分類id
        $cate_id = I('param.cate_id');
        $this->cate_id = $cate_id;

        //是否展開分類
        $hide_cate = false;
        if (ACTION_NAME != 'recycle' && ACTION_NAME != 'draftbox' && ACTION_NAME != 'mydocument') {
            $hide_cate = true;
        }

        //生成每個分類的url
        foreach ($cate as $key => &$value) {
            $value['url'] = 'Article/index?cate_id=' . $value['id'];
            if ($cate_id == $value['id'] && $hide_cate) {
                $value['current'] = true;
            } else {
                $value['current'] = false;
            }
            if (!empty($value['_child'])) {
                $is_child = false;
                foreach ($value['_child'] as $ka => &$va) {
                    $va['url'] = 'Article/index?cate_id=' . $va['id'];
                    if (!empty($va['_child'])) {
                        foreach ($va['_child'] as $k => &$v) {
                            $v['url'] = 'Article/index?cate_id=' . $v['id'];
                            $v['pid'] = $va['id'];
                            $is_child = $v['id'] == $cate_id ? true : false;
                        }
                    }
                    //展開子分類的父分類
                    if ($va['id'] == $cate_id || $is_child) {
                        $is_child = false;
                        if ($hide_cate) {
                            $value['current'] = true;
                            $va['current'] = true;
                        } else {
                            $value['current'] = false;
                            $va['current'] = false;
                        }
                    } else {
                        $va['current'] = false;
                    }
                }
            }
        }



        foreach ($Menus as $key => &$value) {
            if (U($value['url']) == U('Article/mydocument')) {
                unset($value['child']);
                if (!empty($cate)) {
                    foreach ($cate as $value2) {
                        $value['child'][$value2['title']] = $value2['_child'];
                    }
                }
            }
        }
        
        $msn = array();
        foreach ($Menus as $key=> &$value) {
            if ($value['id'] == '2') {
                unset($value['child']);
                $value['child'] = $cate;                
            }
            $msn[$value['id']] = $value;
        }
        unset($value);
//print_r($msn);die;
       // echo '<!--';
        //echo U('Article/mydocument');
        // print_r($cate);
       // print_r($Menus);die;
       // echo '-->';

        $this->assign('nodes', $cate);

        $this->assign('cate_id', $this->cate_id);

        //獲取面包屑信息
        $nav = get_parent_category($cate_id);

        $this->assign('rightNav', $nav);

        //獲取回收站權限
        $show_recycle = $this->checkRule('Admin/article/recycle');
        $this->assign('show_recycle', IS_ROOT || $show_recycle);
        //獲取草稿箱權限
        $this->assign('show_draftbox', C('OPEN_DRAFTBOX'));

        $this->assign('__MENU__', $msn);
    }

    /**
     * 返回後臺節點數據
     * @param boolean $tree    是否返回多維數組結構(生成菜單時用到),為false返回壹維數組(生成權限節點時用到)
     * @retrun array
     *
     * 註意,返回的主菜單節點數組中有'controller'元素,以供區分子節點和主節點
     *
     * @author 朱亞傑 <xcoolcc@gmail.com>
     */
    final protected function returnNodes($tree = true) {
        static $tree_nodes = array();
        if ($tree && !empty($tree_nodes[(int) $tree])) {
            return $tree_nodes[$tree];
        }
        if ((int) $tree) {
            $list = M('Menu')->field('id,pid,title,url,tip,hide')->order('sort asc')->select();
            foreach ($list as $key => $value) {
                if (stripos($value['url'], MODULE_NAME) !== 0) {
                    $list[$key]['url'] = MODULE_NAME . '/' . $value['url'];
                }
            }
            $nodes = list_to_tree($list, $pk = 'id', $pid = 'pid', $child = 'operator', $root = 0);
            foreach ($nodes as $key => $value) {
                if (!empty($value['operator'])) {
                    $nodes[$key]['child'] = $value['operator'];
                    unset($nodes[$key]['operator']);
                }
            }
        } else {
            $nodes = M('Menu')->field('title,url,tip,pid')->order('sort asc')->select();
            foreach ($nodes as $key => $value) {
                if (stripos($value['url'], MODULE_NAME) !== 0) {
                    $nodes[$key]['url'] = MODULE_NAME . '/' . $value['url'];
                }
            }
        }
        $tree_nodes[(int) $tree] = $nodes;
        return $nodes;
    }

    /**
     * 通用分頁列表數據集獲取方法
     *
     *  可以通過url參數傳遞where條件,例如:  index.html?name=asdfasdfasdfddds
     *  可以通過url空值排序字段和方式,例如: index.html?_field=id&_order=asc
     *  可以通過url參數r指定每頁數據條數,例如: index.html?r=5
     *
     * @param sting|Model  $model   模型名或模型實例
     * @param array        $where   where查詢條件(優先級: $where>$_REQUEST>模型設定)
     * @param array|string $order   排序條件,傳入null時使用sql默認排序或模型屬性(優先級最高);
     *                              請求參數中如果指定了_order和_field則據此排序(優先級第二);
     *                              否則使用$order參數(如果$order參數,且模型也沒有設定過order,則取主鍵降序);
     *
     * @param array        $base    基本的查詢條件
     * @param boolean      $field   單表模型用不到該參數,要用在多表join時為field()方法指定參數
     * @author 朱亞傑 <xcoolcc@gmail.com>
     *
     * @return array|false
     * 返回數據集
     */
    protected function lists($model, $where = array(), $order = '', $base = array('status' => array('egt', 0)), $field = true) {
        $options = array();
        $REQUEST = (array) I('request.');
        if (is_string($model)) {
            $model = M($model);
        }

        $OPT = new \ReflectionProperty($model, 'options');
        $OPT->setAccessible(true);

        $pk = $model->getPk();
        if ($order === null) {
            //order置空
        } else if (isset($REQUEST['_order']) && isset($REQUEST['_field']) && in_array(strtolower($REQUEST['_order']), array('desc', 'asc'))) {
            $options['order'] = '`' . $REQUEST['_field'] . '` ' . $REQUEST['_order'];
        } elseif ($order === '' && empty($options['order']) && !empty($pk)) {
            $options['order'] = $pk . ' desc';
        } elseif ($order) {
            $options['order'] = $order;
        }
        unset($REQUEST['_order'], $REQUEST['_field']);

        $options['where'] = array_filter(array_merge((array) $base, /* $REQUEST, */ (array) $where), function($val) {
            if ($val === '' || $val === null) {
                return false;
            } else {
                return true;
            }
        });
        if (empty($options['where'])) {
            unset($options['where']);
        }
        $options = array_merge((array) $OPT->getValue($model), $options);
        $total = $model->where($options['where'])->count();

        if (isset($REQUEST['r'])) {
            $listRows = (int) $REQUEST['r'];
        } else {
            $listRows = C('LIST_ROWS') > 0 ? C('LIST_ROWS') : 10;
        }
        $page = new \Think\Page($total, $listRows, $REQUEST);
        if ($total > $listRows) {
            $page->setConfig('theme', '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END% %HEADER%');
        }
        $p = $page->show();
        $this->assign('_page', $p ? $p : '');
        $this->assign('_total', $total);
        $options['limit'] = $page->firstRow . ',' . $page->listRows;

        $model->setProperty('options', $options);

        return $model->field($field)->select();
    }

}
